package net.flashpunk.graphics
{
	import flash.display.BitmapData;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.VertexBuffer3D;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import net.flashpunk.Camera3D;
	import net.flashpunk.FP;
	import net.flashpunk.Graphic;
	import net.flashpunk.graphics.molehill.ObjLoader;
	import net.flashpunk.graphics.molehill.Quaternion;
	
	/**
	 * Base class for all graphical types that can be drawn by Entity.
	 */
	public class Mesh3D extends Graphic
	{

		
		public static var default_scale:Number = 1;
		

		
		public var rotation:Quaternion = new Quaternion;
		public var index:IndexBuffer3D;
		public var vertex:VertexBuffer3D;
		
		
		
		private var _color:uint = 0xffffffff;
		public var rgba:Vector3D = new Vector3D(1, 1, 1, 1);
		
		
		
		public function set color(c:uint):void
		{
			_color = c;
			rgba.x = FP.getRed(c) / 255.0;
			rgba.y = FP.getBlue(c) / 255.0;
			rgba.z = FP.getGreen(c) / 255.0;
			rgba.w = 1;
		}
		
		/**
		 * Constructor.
		 */
		public function Mesh3D(o:Class = null) 
		{
			if (o == null || o==undefined) return;
			var obj:ObjLoader = new ObjLoader(o,FP.context3d,default_scale);
			index = obj.indexBuffer;
			vertex = obj.positionsBuffer;
			
		}
		
		public static function createCube():Mesh3D
		{
			  var POSITIONS:Vector.<Number> = new <Number>[
            // back face - bottom tri
            -0.5, -0.5, -0.5,
            -0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,
            // back face - top tri
            -0.5, 0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,
 
            // front face - bottom tri
            -0.5, -0.5, 0.5,
            -0.5, 0.5, 0.5,
            0.5, -0.5, 0.5,
            // front face - top tri
            -0.5, 0.5, 0.5,
            0.5, 0.5, 0.5,
            0.5, -0.5, 0.5,
 
            // left face - bottom tri
            -0.5, -0.5, -0.5,
            -0.5, 0.5, -0.5,
            -0.5, -0.5, 0.5,
            // left face - top tri
            -0.5, 0.5, -0.5,
            -0.5, 0.5, 0.5,
            -0.5, -0.5, 0.5,
 
            // right face - bottom tri
            0.5, -0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, 0.5,
            // right face - top tri
            0.5, 0.5, -0.5,
            0.5, 0.5, 0.5,
            0.5, -0.5, 0.5,
 
            // bottom face - bottom tri
            -0.5, -0.5, 0.5,
            -0.5, -0.5, -0.5,
            0.5, -0.5, 0.5,
            // bottom face - top tri
            -0.5, -0.5, -0.5,
            0.5, -0.5, -0.5,
            0.5, -0.5, 0.5,
 
            // top face - bottom tri
            -0.5, 0.5, 0.5,
            -0.5, 0.5, -0.5,
            0.5, 0.5, 0.5,
            // top face - top tri
            -0.5, 0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, 0.5, 0.5
        ];
 
  
 
        /** Triangles of all cubes */
       var TRIS:Vector.<uint> = new <uint>[
            2, 1, 0,    // back face - bottom tri
            5, 4, 3,    // back face - top tri
            6, 7, 8,    // front face - bottom tri
            9, 10, 11,  // front face - top tri
            12, 13, 14, // left face - bottom tri
            15, 16, 17, // left face - top tri
            20, 19, 18, // right face - bottom tri
            23, 22, 21, // right face - top tri
            26, 25, 24, // bottom face - bottom tri
            29, 28, 27, // bottom face - top tri
            30, 31, 32, // top face - bottom tri
            33, 34, 35  // top face - bottom tri
        ];
			var m:Mesh3D = new Mesh3D;
			m.vertex = FP.context3d.createVertexBuffer(36, 3);
            m.vertex.uploadFromVector(POSITIONS, 0, 36);
            m.index = FP.context3d.createIndexBuffer(36);
            m.index.uploadFromVector(TRIS, 0, 36);
				return m;
		}
		
		
		/**
		 * Updates the graphic.
		 */
		override public function update():void
		{
			
		}
		
		/**
		 * Renders the graphic to the screen buffer.
		 * @param	point		The position to draw the graphic.
		 * @param	camera		The camera offset.
		 */
		override public function render(target:BitmapData, point:Point, camera:Point):void
		{
			
		}
		
		/**
		 * Renders the graphic to the screen buffer.
		 * @param	point		The position to draw the graphic.
		 * @param	camera		The camera offset.
		 */
		override public function render3d(point:Vector3D, camera:Camera3D):void
		{
			var matrix:Matrix3D = new Matrix3D;
			matrix.identity();
			 matrix = new Matrix3D(
            new <Number>[
                1, 0, 0, point.x,
                0, 1, 0, point.y,
                0, 0, 1, point.z,
                0, 0, 0, 1
            ]
        );
			//matrix.append(rotation.matrix);
			//matrix.appendTranslation(point.x,point.y,point.z);
			matrix.prepend(camera.worldToClipMatrix);

			//var d:String = "";
			//for each(var n:Number in matrix.rawData) d += n + " ";
			//trace(d);
			var trans:Vector.<Number> = new Vector.<Number>;
			trans.push( rgba.x);
			trans.push( rgba.y);
			trans.push( rgba.z);
			trans.push( rgba.w);
			FP.context3d.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, false);
			FP.context3d.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, trans);
			FP.context3d.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0,trans);
			FP.context3d.setVertexBufferAt(0, vertex, 0, Context3DVertexBufferFormat.FLOAT_3);
            FP.context3d.drawTriangles(index, 0, -1);
		}
		
	}
}